
#include<iostream>

#include"Log.hpp"

//缓冲区设计
// 主要功能：缓冲区中读写数据；套接字的用户缓冲区
// 完整性设计：1.保证数据完整性 2. 发送响应数据时，在套接字可写时发送
#define BUFFER_DEFAULT_SIZE 1024
class Buffer
{
    private:
        std::vector<char> _buffer;
        //读写偏移
        uint64_t _reader_idx;
        uint64_t _writer_idx;
    public:
        Buffer()
        :_reader_idx(0)
        ,_writer_idx(0)
        ,_buffer(BUFFER_DEFAULT_SIZE)
        {}
        char*Begin()
        {
            return &*_buffer.begin();
        }  
        //缓冲写入起始位置
        char*WritePosition()
        {
            return Begin() + _writer_idx;
        }
        char*ReadPosition()
        {
            return Begin() + _reader_idx;
        }
        //缓冲区剩余空间(后半部分)
        uint64_t TailIdleSize()
        {
            return _buffer.size() - _writer_idx;
        }
        //缓冲区前半部分剩余空间
        uint64_t HeadIdleSize()
        {
            return _reader_idx;
        }
        //缓冲区可读数据
        uint64_t ReadAbleSize()
        {
            return _writer_idx - _reader_idx;
        }
        //读偏移向后移动
        void MoveReadOffset(uint64_t len)
        {
            if(len ==0) return;
            //控制在可读数据区域
            assert(len<ReadAbleSize());
            _reader_idx +=len;
        }

        //写偏移后移动
        void MoveWriteOffset(uint64_t len)
        {
            if(len ==0) return;
            assert(len<=TailIdleSize());
            _writer_idx +=len;
        }
        //确保缓冲区写入空间足够
        void EnsureWriteSpace(uint64_t len)
        {
            //后续空间足够
            if(TailIdleSize()>=len)
            {
                return;
            }
            //前后空余空间加一起判断
            if(len<=TailIdleSize() + HeadIdleSize())
            {
                //将目前可读的数据，整体拷贝到开始的位置
                uint64_t rsz = ReadAbleSize();
                std::copy(ReadPosition(),ReadPosition()+rsz,Begin());
                _reader_idx = 0;
                _writer_idx = rsz;
            }
            else 
            {
                DBG_LOG("Resize%ld",_writer_idx+len);
                _buffer.resize(_writer_idx+len);
            }
        }
        //写入数据
        void Write(const void*data,uint64_t len)
        {
            //判断空间是否足够，然后写入
            if(len ==0) return;
            EnsureWriteSpace(len);
            const char*d = (const char*)data;
            std::copy(d,d+len,WritePosition());
        }

        void WriteAndPush(const void*data,uint64_t len)
        {
            Write(data,len);
            MoveWriteOffset(len);
        }

        void WriteString(const std::string&data)
        {
            Write(data.c_str(),data.size());
        }

        void WriteStringAddPush(const std::string&data)
        {
            WriteString(data);
            MoveWriteOffset(data.size());
        }

        void WriteBuffer(Buffer&data)
        {
            Write(data.ReadPosition(),data.ReadAbleSize());
        }

        void WriteBufferAndPush(Buffer&data)
        {
            WriteBuffer(data);
            MoveWriteOffset(data.ReadAbleSize());
        }
        //读取数据
        void Read(void*buf,uint64_t len)
        {
            assert(len<=ReadAbleSize());
            std::copy(ReadPosition(),ReadPosition()+len,(char*)buf);
        }
        void ReadAddPop(void*buf,uint64_t len)
        {
            Read(buf,len);
            MoveReadOffset(len);
        }
        std::string ReadAsString(uint64_t len)
        {
            assert(len<=ReadAbleSize());
            std::string str;
            str.resize(len);
            Read(&str[0],len);
            return str;
        }
        std::string ReadAsStringAndPop(uint64_t len)
        {
            assert(len<=ReadAbleSize());
            std::string str = ReadAsString(len);
            MoveReadOffset(len);
            return str;
        }
        cahr*FindCRLF()
        {
            char*res = (char*)memchr(ReadPosition(),'\n',ReadAbleSize());
            return res;
        }
        std::string GetLine()
        {
            char*pos = FindCRLF();
            if(pos == nullptr) return"";
            return ReadAsString(pos-ReadPosition()+1);//换行符也读取出
        }
        std::string GetLineAddPop()
        {
            std::string str = GetLine();
            MoveReadOffset(str.size());
            return str;
        }
        //缓冲区清空
        void Clear()
        {
            _reader_idx=0;
            _writer_idx=0;
        }

        ~Buffer()
        {}
}

//封装套接字Socket
// 1.避免服务器给断开的客户端发送信息，从而导致程序崩溃，所以对SIGPIPE信号忽略
#define MAX_LISTEN 1024
class NetWork
{
    public:
        NetWork()
        {
            DBG_LOG("SIGPIPE INIT");
            signal(SIGPIPE,SIG_IGN);
        }
}
static NetWork nw;

class Socket
{
    private:
        int _sockfd;
    public:
        Socket():_sockfd(-1){}
        ~Socket(){Close();}
        Socket(int fd):_sockfd(fd){}
        int Fd(){return _sockfd;}

        void Close()//关闭
        {
            if(_sockfd!=-1)
            {
                close(_sockfd);
                _sockfd = -1;
            }
        }

        void NonBlock()//设置非阻塞
        {
            int flag = fcntl(_sockfd,F_GETFL,0);
            fcntl(_sockfd,F_SETFL,flag | O_NONBLOCK);
        }

        bool Create()
        {
            _sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
            if(_sockfd<0)
            {
                ERR_LOG("CREATE SOCKET FAILED!");
                return false;
            }
            return true;
        }

        bool Bind(const std::string&ip,uint16_t port)
        {
            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_port=htons(port);
            addr.sin_addr.s_addr=inet_addr(ip.c_str());
            socklen_t len = sizeof(struct sockaddr_in);
            
            int ret = bind(_sockfd,(struct sockaddr*)&addr,len);
            if(ret<0)
            {
                ERR_LOG("Bind Address Failed!");
                return false;
            }
            return true;
        }

        bool Listen(int backlog = MAX_LISTEN)
        {
            int ret = listen(_sockfd,backlog);
            if(ret<0)
            {
                ERR_LOG("Socket Listen Failed!");
                return false;
            }
            return true;
        }

        //向服务器发起连接
        bool Connect(const std::string&ip,uint16_t port)
        {
            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);
            addr.sin_addr.s_addr = inet_addr(ip.c_str());
            socklen_t len = sizeof(struct sockaddr_in);
            int ret = connect(_sockfd,(struct sockaddr*)&addr,len);
            if(ret < 0)
            {
                ERR_LOG("Connect Server Failed!");
                return false;
            }
            return true;
        }

        int Accept()
        {
            int newfd = accept(_sockfd,NULL,NULL);
            if(newfd < 0)
            {
                ERR_LOG("Socket Accept Failed!");
                return -1;
            }
            return newfd;
        }

        //接收数据
        ssize_t Recv(void*buf,size_t len,int flag =0)
        {
            ssize_t ret = recv(_sockfd,buf,len,flag);

            if(ret<=0)
            {
                //EAGAIN：当前socket缓冲区没有数据，非阻塞特有错误(资源不可用)
                //EINTR：当前socket阻塞等待的时候，被信号打断(操作中断)
                if(errno == EAGAIN || errno == EINTR)
                {
                    return 0;
                }
                ERRLOG("Socket Recv faild!");
                return -1;
            }
            return ret;
        }

        ssize_t NonBlockRecv(void*buf,size_t len)
        {
            //MSG_DONTWAIT:当前接收为非阻塞
            return Recv(buf,len,MSG_DONTWAIT);
        }

        ssize_t Send(const void*buf,size_t len,int flag=0)
        {
            ssize_t ret = send(_sockfd,buf,len,flag);
            if(ret<0)
            {
                if(errno == EAGAIN || errno == EINTR)
                {
                    return 0;
                }
                ERR_LOG("Socket send Faild!");
                return -1;
            }
            return ret;
        }

        ssize_t NonBlockSend(void*buf,size_t len)
        {
            if(len ==0 ) return 0;
            return Send(buf,len,MSG_DONTWAIT);
        }

        //地址端口复用
        void ReuseAddress()
        {   
            //地址复用
            int val=1;
            setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,(void*)&val,sizeof(int));
            //端口复用
            val =1;
            setsockopt(_sockfd,SOL_SOCKET,SO_REUSEPORT,(void*)&val,sizeof(int));
        }

        //创建服务器连接
        bool CreateServer(uint16_t port,const std::string&ip = "0.0.0.0"
        ,bool block_flag = false)
        {
            //创建套接字、绑定地址、监听、非阻塞、地址复用
            if(Create()==false) return false;
            if(block_flag) NonBlock();
            if(Bind(ip,port)==false) return false;
            if(Listen()==false) return false;
            ReuseAddress();
            return true;
        }

        //创建客户端连接
        bool CreateClient(uint16_t port,const std::string&ip)
        {
            //创建套接字、连接服务器
            if(Create()==false) return false;
            if(Connect(ip,port)==false) return false;
            return true;
        }
}

//Reactor线程三大件
class Poller;
class EventLoop;
class Channel  //事件管理(管理新连接的文件描述符)
{
    private:
        int _fd;
        EventLoop*_loop;
        uint32_t _events;//监控事件
        uint32_t _revents;//连接触发事件
        using EventCallback = std::function<void()>
        //回调函数设置:读、写、错误、连接断开、其他事件处理
        EventCallback _read_callback;
        EventCallback _write_callback;
        EventCallback _error_callback;
        EventCallback _close_callback;
        EventCallback _event_callback;

    public:
        Channel(EventLoop*loop,int fd)
        :_fd(fd)
        ,_events(0)
        ,_revents(0)
        ,_loop(loop)
        {}

        int Fd() { return _fd;}
        uint32_t Events() {return _events;} //获取要监控事件
        void SetREvents(uint32_t events) 
        {
            //设置实际就绪事件
            _revents = events;
        }

        //设置回调函数
        void SetReadCallback(const EventCallback&cb) {
            _read_callback = cb;
        }
        void SetWriteCallback(const EventCallback&cb){
            _write_callback = cb;
        }
        void SetErrorCallback(const EventCallback&cb){
            _error_callback = cb;
        }
        void SetCloseCallback(const EventCallback&cb){
            _close_callback = cb;
        }
        void SetEventCallback(const EventCallback&cb){
            _event_callback = cb;
        }

        //判断当前是否监控了读写
        bool ReadAble() {
            return (_events & EPOLLIN);
        }
        bool WriteAble(){
            return (_events & EPOLLOUT);
        }

        //读写事件的监控的开启、关闭、移除
        void EnableRead(){
            _events |= EPOLLIN;
            Update();
        }
        void EnableWrite(){
            _events |=EPOLLOUT;
            Update();
        }
        void DisabelRead(){
            _events&=~EPOLLIN;
            Update();
        }
        void DisableWrite(){
            _events &=~EPOLLOUT;
            Update();
        }
        void DisableAll(){
            _events =0;
            Update();
        }
        void Remove();
        void Update();

        //处理事件
        void HandleEvent()
        {
            if((_revents&EPOLLIN) || (_revents&EPOLLRDHUP) || (_revents&EPOLLPRI))
            {
                //任何事件都调用读回掉
                if(_read_callback) _read_callback();
            }
            if(_revents & EPOLLOUT)
            {
                IF(_write_callback) _write_callback();
            }
            else if(_revents&EPOLLERR)
            {
                if(_error_callback) _error_callback();
            }
            else if(_revents&EPOLLHUP)
            {
                if(_close_callback) _close_callback();
            }
            if(_event_callback) _event_callback();
        }
};
void Channel::Remove(){
    
} 
void Channel::Update(){

}

#define MAX_EPOLLEVENTS 1024
class Poller{
    private:
        int _epfd;
        struct epoll_event _evs[MAX_EPOLLEVENTS];
        std::unordered_map<int,Channel*> _channels;
    private:
        //对epoll操作
        void Update(Channel*channel,int op){
            int fd = channel->Fd();
            struct epoll_event ev;
            ev.data.fd = fd;
            ev.events = channel->Events();
            int ret = epoll_ctr(_epfd,op,fd,&ev);
            if(ret<0){
                ERR_LOG("EPOLLCTL Fail!");
            }
            return;
        }

        //判断一个Channel是否已经添加到监控
        bool HasChannel(Channel*channel){
            auto it = _channels.find(channel->Fd());
            if(it == _channels.end()){
                return false;
            }
            return true;
        }

        public:
            Poller(){
                _epfd = epoll_create(MAX_EPOLLEVENTS);
                if(_epfd<0){
                    ERR_LOG("EPOLL Create Failed!");
                    abort();//退出
                }
            }

            //添加修改监控事件
            void UpdateEvent(Channel*channel)
            {
                bool ret = HasChannel(channel);
                //如果不存在,添加
                if(ret == false){
                    _channels.insert(std::make_pair(channel->Fd(),channel));
                    return Update(channel,EPOLL_CTL_ADD);
                }
                //存在则修改
                return Update(channel,EPOLL_CTL_MOD);
            }

            //移除监控
            void RemoveEvent(Channel*channel)
            {
                auto it = _channels.find(channel->Fd());
                if(it!=_channels.end()){
                    _channels.erase(it);
                }
                Update(channel,EPOLL_CTL_DEL);
            }

            //开始监控返回活跃连接
            void Poll(std::vector<Channel*>*active)
            {
                int nfds = epoll_wait(_epfd,_evs,MAX_EPOLLEVENTS,-1);
                if(nfds<0){
                    if(errno = EINTR){
                        return;
                    }
                    ERR_LOG("Epoll_wait ERROR:%s\n",strerror(errno));
                    abort();
                }
                for(int i=0;i<nfds;i++){
                    auto it = _channels.find(_evs[i].data.fd);
                    assert(it!=_channels.end());//不存在报错
                    it->second->SetREvents(_evs[i].events);//设置就绪事件(就绪的事件放到channel中)
                    active->push_back(it->second);//事件放入任务队列中
                }
                return;
            }
};